package org.windowkit.toolkit.widget.text;

import java.awt.Color;
import java.awt.Dimension;
import java.text.ParseException;

import javax.swing.BorderFactory;
import javax.swing.JFormattedTextField;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.border.EtchedBorder;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;


/**
 *
 * @author Eric Lundin
 */
@SuppressWarnings("serial")
public class PhoneNumberTextField extends FormattedTextField  {

	/** The border to display when the edit is valid.*/
	protected Border validBorder;

	/** The border to display when the edit is invalid.*/
	protected Border invalidBorder;

	/** The tool tip to display when the edit is invalid.*/
	protected static final String INVALID_TOOL_TIP = "ERROR: Invalid Phone Number.";


	/** The formatter to use in this textfield.*/
	protected PhoneNumberMaskFormatter formatter;

	/**
	 * @param componentID
	 *            The unique componentID
	 */
	public PhoneNumberTextField() {
		this(null);
	}

	/**
	 * Creates a phoneNumberTextField which considers a phone number with at
	 * least 10 digits valid.
	 *
	 * @param initialNumber
	 *            The initial number to display.
	 * @param componentID
	 *            The unique id of this component.
	 */
	public PhoneNumberTextField(final String initialNumber) {
		this(initialNumber, 10);
	}

	/**
	 * @param initialNumber
	 *            The initial number to display.
	 * @param minimumDigits
	 *            The minimum number of digits to consider a phone number valid.
	 * @param componentID
	 *            The unique id of this component.
	 */
	public PhoneNumberTextField(final String initialNumber, final int minimumDigits) {
		super(new PhoneNumberMaskFormatter(minimumDigits));
		formatter = (PhoneNumberMaskFormatter) getFormatter();
		setValue(initialNumber);
		setFocusLostBehavior(JFormattedTextField.COMMIT);
		initBorders();
		addCaretListener(new SPhoneNumberCaretListener());
		setComponentSize();
	}

	/**
	 * Set our size
	 */
	private void setComponentSize() {
		int width = getFontMetrics(getFont()).stringWidth(
				formatter.getMask() + "   ");
		setPreferredSize(new Dimension(width, (int) getPreferredSize()
				.getHeight()));
	}

	/**
	 * Will determine whether the edit is valid or not and set the border to
	 * relflect the validity.
	 */
	protected void setBorderByValidity() {
		if (isEditValid()) {
			setShowValid(true);
		}
		else {
			setShowValid(false);
		}
	}

	/**
	 * Initialize the borders for valid/invalid edits.
	 */
	protected void initBorders() {
		validBorder = UIManager.getBorder("TextField.border");
		invalidBorder = BorderFactory.createEtchedBorder(EtchedBorder.LOWERED,
				Color.RED, UIManager.getColor("TextField.shadow"));
		setBorder(validBorder);
	}

	/**
	 * Sets the appropriate border based on the value of isValid.
	 *
	 * @param isValid
	 *            Whether the currently edited value is valid.
	 */
	public void setShowValid(final boolean isValid) {
		if (isValid) {
			setBorder(validBorder);
			setToolTipText(null);
		} else {
			setBorder(invalidBorder);
			setToolTipText(INVALID_TOOL_TIP);
		}
	}

	/**
	 * Sets the minimum number of digits. For example to require at least the
	 * are code specify 3. To require a phone number with an optional extension
	 * specify 10.
	 *
	 * @param minimumDigits
	 *            The minimum number of digits needed to be valid.
	 */
	public void setMinimumNumberOfDigits(final int minimumDigits) {
		formatter.setMinimumNumberOfDigits(minimumDigits);
	}

	/**
	 * Sets the value to the given phone number. If the phone number is invalid
	 * the value will be displayed as the placehodler (___) ___-____ x_____.
	 * When entering the phone number only the order of the numbers matters.
	 * I.E. 2813308004 is the same as (281) 330-8004 x_____ is the same as
	 * 281----3+3+0+8+0+0+4+
	 */
	@Override
    public void setValue(final Object value) {
		super.setValue(value);
		try {
			commitEdit();
		} catch (ParseException e) {
			super.setValue(null);
		}
	}

	/**
	 * Returns the current phone number or null if the phone number is invalid.
	 * The phone number will be formatted in the following fashion (281)
	 * 330-8004 x12345.
	 */
	@Override
	public Object getValue() {
		Object value = null;
		if (isEditValid()) {
			value = super.getValue();
		}
		return value;
	}

	/**
	 * Will determine edit's validity and set the border appropriately.
	 *
	 * @author Eric Lundin
	 */
	private class SPhoneNumberCaretListener implements CaretListener {
		public void caretUpdate(final CaretEvent e) {
			setBorderByValidity();
		}
	}

}